package com.miplus.ccrm.core.service.action;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.*;
import com.miplus.ccrm.core.controller.vo.action.*;
import com.miplus.ccrm.core.controller.vo.conf.WfNextStepVo;
import com.miplus.ccrm.core.controller.vo.credit.CrdCmdResVo;
import com.miplus.ccrm.core.mapper.ConCustomerMapper;
import com.miplus.ccrm.core.mapper.FiCreditcasesMapper;
import com.miplus.ccrm.core.pojo.*;
import com.miplus.ccrm.core.mapper.FiDeductMapper;
import com.miplus.ccrm.core.service.ExportService;
import com.miplus.ccrm.core.service.FiWorkFlowCase;
import com.miplus.ccrm.core.service.collect.FiImportHistService;
import com.miplus.ccrm.core.service.collect.FiTaskService;
import com.miplus.ccrm.core.service.conf.MsgAlertsService;
import com.miplus.ccrm.core.service.crd.CrdCommand;
import com.miplus.ccrm.core.service.crd.CreditCardService;
import com.miplus.ccrm.core.service.iou.IouBillService;
import com.miplus.ccrm.core.service.iou.IouCommand;
import com.miplus.ccrm.core.service.strategy.CpCalllistService;
import com.miplus.ccrm.core.service.strategy.CpStrategyService;
import com.miplus.ccrm.core.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
* @author pc
* @description 针对表【fi_deduct(划扣申请表)】的数据库操作Service实现
* @createDate 2024-04-24 19:18:31
*/
@Slf4j
@Service
public class FiDeductServiceImpl extends MPJBaseServiceImpl<FiDeductMapper, FiDeduct>
    implements FiDeductService{
    @Resource
    private FiTaskService fiTaskService;
    @Resource
    private CpCalllistService cpCalllistService;
    @Resource
    private FiWorkFlowCase fiWorkFlowCase;
    @Resource
    private MsgAlertsService msgAlertsService;
    @Resource
    private FiCreditcasesMapper fiCreditcasesMapper;
    @Resource
    private ConCustomerMapper conCustomerMapper;
    @Resource
    private CreditCardService creditCardService;
    @Resource
    private IouCommand iouCommand;
    @Resource
    private IouBillService iouBillService;
    @Resource
    private CpStrategyService cpStrategyService;
    @Resource
    private ExportService exportService;
    @Resource
    private FiImportHistService fiImportHistService;

    @Override
    public IPage<FiDedResVo> fiDeductList(JSysUser user, FiApplyReqVo paras)
    {
        String $usrid=user.getUsrid();
        String cardstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_CARD);
        String idnostar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_IDNO);
        MPJLambdaWrapper<FiDeduct> quyWrapper=new MPJLambdaWrapper<FiDeduct>()
                .selectAs("fun_getnames('FI.DEDUCT.STATUS',t.status)", FiDedResVo::getStatusdsc)
                .selectAs("fun_getnames('FI.DEDUCT.REASON',t.applyreason)", FiDedResVo::getApplyreasondsc)
                .selectAs("(select cl.wfid from cp_calllist cl where cl.clid=t.clid)", FiDedResVo::getWfid)
                .selectAs("fun_getgrpname(t.applyusr)",FiDedResVo::getApplygrpname)
                .selectAs(String.format("fi_starSecu('%s','%s',t.idnumber,'%s')", $usrid, JUsrPerm.DISSTAR_IDNO, idnostar), FiDedResVo::getIdnumber)
                .select(FiDeduct::getApplynumber,FiDeduct::getApplyreason,FiDeduct::getApplydt,FiDeduct::getFicaseid,FiDeduct::getApplydsc,FiDeduct::getApplyusr,
                        FiDeduct::getClid, FiDeduct::getAmount,FiDeduct::getCanceldt,FiDeduct::getCancelusr,FiDeduct::getConfirmusr,
                        FiDeduct::getConfirmdt,FiDeduct::getConfirmdsc,FiDeduct::getStatus,FiDeduct::getTasknumber,FiDeduct::getCustname,FiDeduct::getCmdseqno)
                .apply("fc_hasApplyView(t.applynumber,'SYS_CARDDED',t.applyusr,{0},t.status,t.confirmusr)>0",$usrid)
                .apply(JPubUtils.IsNotEmpty(paras.getApplygrp()),"fc_hasUsrInGroup(t.applyusr,{0})>0",paras.getApplygrp())
                .eq(JPubUtils.IsNotEmpty(paras.getFicaseid()), FiDeduct::getFicaseid,paras.getFicaseid())
                .eq(JPubUtils.IsNotEmpty(paras.getStatus()),FiDeduct::getStatus,paras.getStatus())
                .eq(JPubUtils.IsNotEmpty(paras.getApplyusr()),FiDeduct::getApplyusr,paras.getApplyusr())
                .between(JPubUtils.IsNotEmpty(paras.getStartdt()), FiDeduct::getApplydt,JPubUtils.StringToDate(paras.getStartdt()),JPubUtils.StringToDate(paras.getEnddt()))
                .orderByAsc(FiDeduct::getApplydt);

        if(JPubUtils.enSysType==EnumSysType.ious){
            quyWrapper.selectAs(FiDeduct::getCollectno, FiDedResVo::getCollectno);
        }
        else{
            quyWrapper.selectAs(String.format("fi_starSecu('%s','%s',t.collectno,'%s')", $usrid, JUsrPerm.DISSTAR_CARD, cardstar), FiDedResVo::getCollectno);
        }

        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                FiDedResVo.class,
                quyWrapper
        );
    }

    @Override
    @Transactional
    public CmdResVo fiDeductAdd(String $usrid, FiDedAddVo paras)
    {
        //1=待审核
        List<FiDeduct> fiDeducts=selectJoinList(FiDeduct.class,
                new MPJLambdaWrapper<FiDeduct>()
                        .eq(FiDeduct::getFicaseid,paras.getFicaseid())
                        .in(FiDeduct::getStatus,
                                EnumConfirmStatus.New.value,EnumConfirmStatus.Pending.value,
                                EnumConfirmStatus.Process.value)
        );
        //相同的案件正在审核中
        if(JPubUtils.IsNotEmpty(fiDeducts)){
            throw new ServiceException(EnumRCode.DataProcess.value, EnumRCode.DataProcess.name);
        }
        String clid=paras.getClid();
        if(JPubUtils.IsEmpty(clid)){
            clid="SYS_CARDDED"; //此任务是系统配置任务，不能delete
        }
        cpCalllistService.checkActionOk(paras.getFicaseid(),clid,EnumFiChannel.Deduction);

        Integer wfid=cpCalllistService.getCalllistWfID(clid);

        FiCreditcases creditcases=fiCreditcasesMapper.selectById(paras.getFicaseid());
        String cardno=""; //客户端传过来的借记卡可能是带星加密的
        String collectno=paras.getCollectno();
        ConCustomer customer=conCustomerMapper.selectById(creditcases.getCustomernumber());
        String custname=customer.getCustname();
        String idnumber=customer.getOpenacctcertno();
        if(JPubUtils.enSysType==EnumSysType.credit) {
            cardno=customer.getDebitcardno();
            collectno = creditCardService.getAccOpenLastCardNo(creditcases.getCreditAcct());
        }
        ICmdResVo resVo=new ICmdResVo();
        if(wfid<=0){
            resVo=cmdDeduction(collectno,idnumber,custname,cardno,paras.getAmount());
        }
        int tasknumber=fiTaskService.addTask($usrid,clid,paras.getFicaseid(),EnumFiChannel.Deduction.value);

        int ret=0;
        log.info("applyAdd:clid={},ficase={},tasknumber={},wfid={}",clid,paras.getFicaseid(),tasknumber,wfid);

        FiDeduct fi = new FiDeduct();
        fi.setClid(clid);
        fi.setApplyreason(paras.getApplyreason());
        fi.setFicaseid(paras.getFicaseid());
        fi.setApplydsc(paras.getApplydsc());
        fi.setTasknumber(tasknumber);
        fi.setCardno(cardno);
        fi.setCollectno(collectno);
        fi.setAmount(paras.getAmount());
        if(wfid>0) {
            fi.setStatus(EnumConfirmStatus.New.value); //新建
        }
        else {
            //划扣操作成功失败在task里面显示
            fi.setStatus(EnumConfirmStatus.Process.value);
        }
        fi.setApplydt(new Date());
        fi.setApplyusr($usrid);
        fi.setCustname(custname);
        fi.setIdnumber(idnumber);
        if(wfid<=0) {
            fi.setCmdseqno(resVo.getSeqNo());
        }
        ret=baseMapper.insert(fi);
        int applynumber=fi.getApplynumber();
        if(wfid>0){
            //wfid=0 表示此任务clid没有配置工作流，前台可以根据是否有wfid显示不通的审批流程或状态
            String status=fiWorkFlowCase.doCreate($usrid,wfid,applynumber,tasknumber);
            fi = new FiDeduct();
            fi.setApplynumber(applynumber);
            fi.setStatus(Integer.parseInt(status)); //处理中
            baseMapper.updateById(fi);
        }else{
            setDeductResult(resVo,clid,
                    tasknumber,
                    $usrid,
                    $usrid,
                    paras.getAmount()
            );
        }

        return new CmdResVo(ret,Integer.toString(applynumber));
    }

    @Override
    public CmdResVo fiDeductCancel(String $usrid, FiApplyCancelVo paras)
    {
        FiDeduct fi=baseMapper.selectById(paras.getApplynumber());
        if(JPubUtils.IsNotEmpty(fi.getTasknumber())){
            fiTaskService.updateStatus(fi.getTasknumber(),$usrid,"X");
        }
        else{
            log.warn("applyCancel:getTasknumber.isnull");
        }
        Integer wfid=cpCalllistService.getCalllistWfID(fi.getClid());
        fiWorkFlowCase.doCancel($usrid,wfid,fi.getApplynumber());

        fi = new FiDeduct();
        fi.setApplynumber(paras.getApplynumber());
        fi.setStatus(EnumConfirmStatus.Cancel.value); //取消
        fi.setCancelusr($usrid);
        fi.setCanceldt(new Date());
        int ret=baseMapper.updateById(fi);

        return new CmdResVo(ret,fi.getApplynumber().toString());
    }

    @Override
    public CmdResVo fiDeductConfirm(String $usrid, FiApplyConfirmVo paras)
    {
        boolean confirmend=true;
        String okstatus=paras.getActionid().toString();
        FiDeduct fiDeduct=baseMapper.selectById(paras.getApplynumber());
        if(JPubUtils.IsNotEmpty(paras.getCaseactid())){
            //需要走工作流
            WfNextStepVo wfNextStepVo=fiWorkFlowCase.doExec($usrid,paras.getCaseactid(),
                    paras.getActionid(),paras.getWfcaseid(),paras.getConfirmdsc()
            );
            okstatus=wfNextStepVo.getStatus();

            //可能有多级审核,3=审核全部完成
            if(!JPubUtils.IsEqual(wfNextStepVo.getType(), EnumWorkFlowStep.End.value)) {
                confirmend=false;
            }
        }
        else{
            Integer wfid=cpCalllistService.getCalllistWfID(fiDeduct.getClid());
            if(wfid==null||wfid==0){//不使用工作流,这种情况下okstatus就是字典ID，直接写审核结果
                log.info("fiDeductConfirm.nouse workflow：okstatus={}",okstatus);
            }
            else{//可能配置错误或网络引起的，2024-08-29
                log.warn("fiDeductConfirm.nofind wf caseactid.");
                throw new ServiceException(EnumRCode.WfDataErr.value, EnumRCode.WfDataErr.name);
            }
        }
        ICmdResVo resVo=new ICmdResVo();
        //单纯就是审批流程，结果后续操作就在这里写，如果有后续反馈的，在result里面写，比如外访
        if(JPubUtils.IsNotEmpty(fiDeduct.getTasknumber())&&confirmend) {
            fiTaskService.updateStatus(
                    fiDeduct.getTasknumber(),
                    $usrid,
                    fiWorkFlowCase.getPassStatus(okstatus)
            );

            msgAlertsService.msgAlertAdd(EnumFiChannel.Deduction,
                    fiDeduct.getApplyusr(),
                    $usrid,
                    EnumUtil.ConfirmStatusName(okstatus)
            );

            if(JPubUtils.IsEqual(okstatus,EnumConfirmStatus.Pass.value)) {//审核通过
                resVo=cmdDeduction(fiDeduct.getCollectno(),
                        fiDeduct.getIdnumber(),
                        fiDeduct.getCustname(),
                        fiDeduct.getCardno(),
                        fiDeduct.getAmount()
                );
                okstatus=setDeductResult(resVo,fiDeduct.getClid(),
                        fiDeduct.getTasknumber(),
                        fiDeduct.getApplyusr(),
                        $usrid,
                        fiDeduct.getAmount()
                ).toString();
            }
        }

        FiDeduct fi = new FiDeduct();
        fi.setApplynumber(paras.getApplynumber());
        fi.setStatus(Integer.parseInt(okstatus));
        fi.setConfirmusr($usrid);
        fi.setConfirmdt(new Date());
        fi.setConfirmdsc(paras.getConfirmdsc());
        if(JPubUtils.IsNotEmpty(resVo.getSeqNo())){
            fi.setCmdseqno(resVo.getSeqNo());
        }
        int ret=baseMapper.updateById(fi);

        return new CmdResVo(ret,paras.getApplynumber().toString());
    }

    private ICmdResVo cmdDeduction(String collectno, String idnumber, String custname, String cardno, BigDecimal amt)
    {
        ICmdResVo resVo=new ICmdResVo();
        if(JPubUtils.enSysType==EnumSysType.ious){
            String channelcode=iouBillService.getChannelCode(collectno);
            resVo=iouCommand.cmdDeduction(collectno,idnumber,custname,amt,channelcode);
        }
        else{
            CrdCmdResVo resVo2=CrdCommand.crdCarDeduction(cardno, collectno, amt);
            resVo.setRespCode(resVo2.getRespCode());
            resVo.setRespCodeDesc(resVo2.getRespCodeDesc());
        }

        return resVo;
    }

    private EnumConfirmStatus setDeductResult(ICmdResVo resVo,String clid,Integer tasknumber,String applyusr,String $usrid,BigDecimal amt)
    {
        String status=cpStrategyService.getTaskStatus(clid,resVo.getRespCode());

        fiTaskService.saveTask(tasknumber,
                $usrid,
                resVo.getRespCode(),
                "划扣金额："+amt.toString(),
                status);

        msgAlertsService.msgAlertAdd(EnumFiChannel.Deduction, applyusr, $usrid, status);
        if(JPubUtils.IsEqual(status,EnumTaskStatus.R.toString())){
            return EnumConfirmStatus.Finish;
        }
        else if(JPubUtils.IsEqual(status,EnumTaskStatus.F.toString())) {
            return EnumConfirmStatus.Fail;
        }
        else return EnumConfirmStatus.Process;
    }

    @Override
    public ICmdResVo fiDeductRefresh(String $usrid,Integer applynumber)
    {
        FiDeduct fiDeduct=baseMapper.selectById(applynumber);
        if(fiDeduct==null){
            log.warn("fiDeductRefresh.nofind applynumber={}",applynumber);
            throw new ServiceException(EnumRCode.NoFindSource.value, EnumRCode.NoFindSource.name);
        }
        String seqno=fiDeduct.getCmdseqno();
        if(JPubUtils.IsEmpty(seqno)){
            log.warn("fiDeductRefresh.nofind seqno");
            throw new ServiceException(EnumRCode.NoFindSource.value, EnumRCode.NoFindSource.name);
        }
        ICmdResVo resVo=iouCommand.refDeductStatus(fiDeduct.getCollectno(),
                fiDeduct.getIdnumber(),fiDeduct.getCustname(),seqno
        );
        String status=cpStrategyService.getTaskStatus("SYS_CARDDED",resVo.getRespCode());

        fiTaskService.saveTask(fiDeduct.getTasknumber(), $usrid,resVo.getRespCode(),null,status);

        EnumConfirmStatus en=EnumConfirmStatus.Process;
        if(JPubUtils.IsEqual(status,EnumTaskStatus.R.toString())){
            en=EnumConfirmStatus.Finish;
        }
        else if(JPubUtils.IsEqual(status,EnumTaskStatus.F.toString())) {
            en=EnumConfirmStatus.Fail;
        }

        FiDeduct fi = new FiDeduct();
        fi.setApplynumber(applynumber);
        fi.setStatus(en.value);
        baseMapper.updateById(fi);

        return resVo;
    }

    @Override
    public CmdResVo expDeductList(JSysUser user, FiApplyReqVo paras, HttpServletResponse response)
    {
        String $usrid = user.getUsrid();
        int pagesize = paras.getPageSize();
        if (pagesize > JPubUtils.exportMaxCount) {
            paras.setPageSize(JPubUtils.exportMaxCount);
        }
        log.info("expSmsList:pagesize={}",pagesize);

        IPage<FiDedResVo> pages=fiDeductList(user,paras);
        ArrayList arr=new ArrayList();

        String exptempid=JPubUtils.getExpTempID(paras.getExpfilename(),"划扣审批数据");
        String filename=JPubUtils.getExpFileName(
                paras.getExpfilename(),exptempid
        );
        pages.convert(u->{
            HashMap map=JPubUtils.toExportMap(u);
            if(map!=null) arr.add(map);
            return u;
        });
        CmdResVo resVo=exportService.ToExcel(
                response,
                arr,
                paras.getExpidlist(),
                paras.getExpnamelist(),
                filename,
                $usrid
        );

        int okcount=resVo.getCount();
        if(okcount>0){
            fiImportHistService.AddExportHist(
                    resVo.getKeyId(),
                    $usrid,
                    exptempid,
                    filename,
                    okcount
            );
        }
        arr.clear();

        return resVo;
    }
}




